package com.cmes.core.utils.dict;

import com.cmes.core.utils.StringPool;
import com.cmes.core.utils.StringUtils;

import java.util.EnumSet;
import java.util.Set;
import java.util.stream.Stream;

/**
 * 字典工具类
 * <p>提供对 {@link Dict} 实现类的工具方法</p>
 *
 * @author Bruce.Gong
 * @since 1.0.0-SNAPSHOT
 */
public class DictUtils {

    /**
     * 根据字典类类型获取该字典的所有成员
     *
     * @param clazz 字典类类型
     * @return 字典类的所有成员
     */
    public static <E extends Enum<E> & Dict<K>, K> EnumSet<E> values(Class<E> clazz) {
        return EnumSet.allOf(clazz);
    }

    /**
     * 根据键值获取字典
     *
     * @param clazz 字典类类型
     * @param code  键
     * @return 字典
     */
    public static <E extends Enum<E> & Dict<K>, K> E parse(Class<E> clazz, K code) {
        if (code == null) {
            return null;
        }
        EnumSet<E> set = values(clazz);
        for (E item : set) {
            if (item.match(code)) {
                return item;
            }
        }
        return null;
    }

    /**
     * 根据键值获取字典
     *
     * @param clazz 字典类类型
     * @param code  键
     * @return 字典
     */
    public static <E extends Enum<E> & Dict<K>, K> String getValue(Class<E> clazz, K code) {
        E dict = parse(clazz, code);
        return dict == null ? StringPool.EMPTY : dict.getValue();
    }

    /**
     * 根据键值获取字典，如果 {@code code} 为数字类型，也可以通过字符串进行匹配
     *
     * @param clazz 字典类类型
     * @param code  键
     * @return 字典
     */
    public static <E extends Enum<E> & Dict<K>, K> E parseString(Class<E> clazz, String code) {
        if (StringUtils.isBlank(code)) {
            return null;
        }
        return parseString(values(clazz), code);
    }

    /**
     * 根据键值获取字典，如果 {@code code} 为数字类型，也可以通过字符串进行匹配
     *
     * @param enumSet 字典类类型
     * @param code    键
     * @return 字典
     */
    public static <E extends Enum<E> & Dict<K>, K> E parseString(Set<E> enumSet, String code) {
        if (StringUtils.isBlank(code)) {
            return null;
        }
        for (E item : enumSet) {
            if (item.matchString(code)) {
                return item;
            }
        }
        return null;
    }

    /**
     * 根据键值获取字典
     *
     * @param clazz 字典类类型
     * @param code  键
     * @return 字典
     */
    public static <E extends Enum<E> & Dict<?>> E parseObject(Class<E> clazz, Object code) {
        if (code == null) {
            return null;
        }
        EnumSet<E> set = EnumSet.allOf(clazz);
        for (E item : set) {
            if (item.matchObject(code)) {
                return item;
            }
        }
        return null;
    }

    /**
     * 判断键与字典是否匹配
     *
     * @param code 键
     * @param item 字典
     * @return true | false
     */
    public static <T extends Enum<T> & Dict<V>, V> boolean match(V code, T item) {
        return item != null && item.match(code);
    }

    /**
     * 判断键能否匹配多个字典中的任意一个
     *
     * @param code  键
     * @param items 字典
     * @return true | false
     */
    public static <T extends Enum<T> & Dict<V>, V> boolean matchAny(V code, T... items) {
        return items != null && items.length > 0 && Stream.of(items).anyMatch(v -> v.match(code));
    }

    /**
     * 判断字典是否是提供的多个字典中的一个
     *
     * @param code  字典
     * @param items 字典
     * @return true | false
     */
    public static <T extends Enum<T> & Dict<V>, V> boolean matchAny(T code, T... items) {
        return items != null && items.length > 0 && Stream.of(items).anyMatch(v -> v.match(code));
    }

}
